Thread: I need to create a function to read a csv file of a database of monsters [help]

  1. #1
    Registered User
    Join Date
    Nov 2021
    Posts
    2

    I need to create a program to read a csv file of a database of monsters [help]

    This is my first year of coding and i'm having trouble with this program. This is the code I completed with the pseudocode. The name is monster_sortdb.c and I need to run it with a file called monsters.csv using the command monster_sortdb < monsters.csv in terminal. My problem is, when I run this program it just returns nothing (what needs to be outputted is shown below). I'm not sure where to look or what sections i'm doing incorrectly. i've tried adjusting the first two functions and I think maybe the problem is with the commas? I'm not sure if I did them correctly but they did compile. I've tried adjusting the loadDatabase function by moving things in and out of brackets but that didn't seem to do the trick either.




    The csv file is here: monsters.csv - Google Drive


    Whats supposed to happen is this:


    "Visually inspect the output printed to your terminal screen. The first line of the output (which name of the attributes for each column in our “table”) should match exactly with the first line of the original CSV file. The monsters should also now be sorted by the year of their film, and each attribute should only be separated by commas (no extra spaces between different attributes)."


    But when I run the program nothing shows up at all. I think there might be a problem with one of the functions and messing up the reading of the csv file into my program. Just can't seem to locate where my problem is. Thanks for any help!

    here are the first two rows of the csv file for preview, after count dracula are just other villains filled out.The CSV file that was given leads to the full spreadsheet.


    Name Film Year Weakness Defeated by Rating
    Count Dracula Dracula 1931 wooden stake Van Helsing 7.6

    here is the code:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    
    #define NAME_SIZE 15
    #define FILM_SIZE 50
    #define WEAKNESS_SIZE 25
    #define defeatedBy_SIZE 30
    
    typedef struct {
      char name[NAME_SIZE];
      char film[FILM_SIZE];
      int year;
      char weakness[WEAKNESS_SIZE];
      char defeatedBy[defeatedBy_SIZE];
      float rating;
    
    } Monster;
    
    /*
     * Declaring storage for the database.
     */
    #define MAX_MONSTERS 1024       /* should be big enough */
    Monster monsters[MAX_MONSTERS];
    
    void printCsvHeader(void)
    /* print a CSV-compatible "monster" header to standard output */
    {
    
      /*
       * ASSIGNMENT
       *
       * print each attribute name of the monster in order, followed by
       *  a ",", except for the last one, which should be followed by a
       *  newline ("\n").
       */
      printf("name,film,year,weakness,defeatedBy,rating\n");
    
    
    }
    
    void printCsvRow(Monster monster)
    /* print a CSV-compatible "monster" row to standard output */
    {
      /*
       * ASSIGNMENT
       *
       * print each attribute of the monster in order, followed by a
       *  ",", except for the last one, which should be followed by a
       *  newline ('\n').
       */
    
      printf("%s,", monster.name);
      printf("%s,", monster.film);
      printf("%d,", monster.year);
      printf("%s,", monster.weakness);
      printf("%s,", monster.defeatedBy);
      printf("%f\n", monster.rating);
    
    
    }
    
    void saveDatabase(Monster monsters[])
    {
      /*
       * ASSIGNMENT
       *
       * print the CSV header with printCsvHeader()
       * for each monster in the monster database,
       *     print it with printCsvRow()
       */
    
      printCsvHeader();
    
      int i;
    
      for (i = 0; i < MAX_MONSTERS; i++) {
        printCsvRow(monsters);
      }
    
    }
    
    int foundColumnName(char columnName[], char followedBy)
    /* helper function used to read an expected column name */
    {
      char buffer[2048];            /* longer than the longest possible column name */
      /*
       * The "%[^,\n]s" format string tells scanf() to accept anything
       * that's not a ',' or a '\n' as part of a string. Those two
       * characters *separate* data in a CSV file.
       *
       * After reading and verifying the column name, we call getchar()
       * to verify that it's followed by the char `followedBy`,
       * returning 0 if any of these errors are detected.
       */
      if (scanf("%[^,\n]s", buffer) != 1  /* didn't read one item */
          || strcmp(buffer, columnName) != 0  /* doesn't match `columnName` */
          || getchar() != followedBy) { /* not followed by expected char */
        return 0;
      }
      return 1;
    }
    
    
    int scanCsvHeader(void)
    /* scans a CSV-compatible "monster" header for compatibility */
    {
      /*
       * This function will read a CSV header line and verify its
       * correctness. Return 1 if it is correct and 0 if it is not.
       *
       * You need to confirm that each header field is occurring in
       * order.  The function foundColumnName() can do the dirty work
       * here. All you need to do is call it properly.
       *
       * Here is how you do it for the first field in the header.
       */
      if (!foundColumnName("name", ','))
        return 0;
      /*
       * ASSIGNMENT
       *
       * Now do the same for the remaining attribute names in the
       * Monster struct, except that the last attribute should have the
       * `followedBy` argument be a newline ('\n'), not a comma.
       *
       * At the very end, all of the column names have been matched, so
       * return 1 to indicate success.
       */
    
      if (!foundColumnName("film", ','))
        return 0;
    
      if (!foundColumnName("year", ','))
        return 0;
    
      if (!foundColumnName("weakness", ','))
        return 0;
    
      if (!foundColumnName("defeatedBy", ','))
        return 0;
    
      if (!foundColumnName("rating", '\n'))
        return 0;
    
      return 1;
    }
    
    
    int scanCsvRow(Monster * monster)
    /* reads a Monster row from a CSV file */
    {
      /*
       * This function calls scanf() to read every attribute on the row
       * in order using the appropriate format. The result of scanf()
       * will be 1 if the data is read successfully.
       *
       * For example, here's how you read the name. For string
       * attributes *only*, we again use the "%[^,\n]s" format string to
       * read a sequence of any characters except comma and newline.
       * Other attribute types can use the usual "%d", "%f", or
       * whatever.
       */
      if (scanf("%[^,\n]s", monster->name) != 1)
        return 0;
      getchar();                    /* skip the following comma or newline (we could check this) */
      /*
       * ASSIGNMENT
       *
       * Now do the same for the remaining attribute values in the
       * Monster struct. Be sure to that you always pass either a
       * reference (i.e. prefaced with "&") or the name of an array to
       * scanf().
       *
       * At the very end, all of the column names have been matched, so
       * return 1 to indicate success.
       */
    
      if (scanf("%[^,\n]s", monster->film) != 1)
        return 0;
      getchar();
    
      if (scanf("%d", &monster->year) != 1)
        return 0;
      getchar();
    
      if (scanf("%[^,\n]s", monster->weakness) != 1)
        return 0;
      getchar();
    
      if (scanf("%[^,\n]s", monster->defeatedBy) != 1)
        return 0;
      getchar();
    
      if (scanf("%f", &monster->rating) != 1)
        return 0;
      getchar();
    
      return 1;
    }
    
    
    int loadDatabase(void)
    /* reads a CSV monster database on standard input, returns the number of members */
    {
      /*
       * ASSIGNMENT
       *
       * Here's the pseudocode:
       *
       * call `scanCsvHeader()` to read the CSV header
       * if the CSV header is not correct,
       *     return 0
       * set `count` to 0
       * repeat the following indefinitely,
       *     call `scanCsvRow()` to read a new monster into the database
       *      at `monsters[count]`
       *     if it's not successful (i.e. at end-of-file),
       *         break out of the loop
       *     increment `count`
       * make `monsters[count].name` a zero-length string
       * return `count`
       */
    
    
      if (scanCsvHeader() == 0) {
        return 0;
    
      }
    
      int count = 0;
    
      while (1 == 1) {
    
        if (scanCsvRow(&monsters[count]) == 0) {
          break;
        }
        count++;
      }
    
      strcpy(monsters[count].name, "\0");
    
    
    
      return count;
    
    }
    
    
    int compareMonstersByYear(const void *monster0_vp, const void *monster1_vp)
    {
      /*
       * Don't worry about this function for now. All you need to know
       * is that it's used by `qsort()` for sorting.
       */
      const Monster *monster0_p = monster0_vp;
      const Monster *monster1_p = monster1_vp;
    
      /* sort monsters by year of film release */
      return monster0_p->year - monster1_p->year;
    }
    
    
    int main(void)
    {
      int monsterCount;
    
      monsterCount = loadDatabase();
      if (monsterCount > 0) {
        qsort(monsters, monsterCount, sizeof(Monster), compareMonstersByYear);
        saveDatabase(monsters);
      }
      return 0;
    }
    Last edited by spookybandit; 11-07-2021 at 01:35 AM. Reason: Removed crayola colour from the code.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    First off, there's no need to bold all the text, and we can read regular text just fine.
    And when you post code, make sure you use copy-as-text (in your IDE) and/or paste-as-text (in the browser). Whacky colour schemes copied with the so-called "smart" features are a mess when posted on a forum.

    > I'm not sure if I did them correctly but they did compile.
    What did you type to compile the file?

    > using the command monster_sortdb.c < monsters.csv
    Which would be file, if you used the name of the compiled program, not the name of the source file.

    So perhaps you want
    Code:
    gcc -o monster_sortdb monster_sortdb.c
    ./monster_sortdb < monsters.csv
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Nov 2021
    Posts
    2
    Hello, sorry about the colors and bolded text. I made sure to correct the bold.

    I compiled with:

    gcc -Wall monster_sortdb.c -o monster_sort

    and ran it with

    monster_sort < monsters.csv

    which still gives me nothing.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    So start going through the code debugging the issues.

    Eg.
    Code:
      if (scanCsvHeader() == 0) {
        print("DEBUG: scanCsvHeader returned 0\n");
        return 0;
      }
    If you can figure out where it starts failing, then you can start figuring out solutions.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    This format is wrong: "%[^,\n]s"
    Remove the s since it is not part of the [ ] format.
    Having the s there means it needs to match an actual s character or it fails!
    A little inaccuracy saves tons of explanation. - H.H. Munro

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 04-14-2019, 04:49 AM
  2. Read file, Create struct 5x5 numbers
    By Leite33 in forum C Programming
    Replies: 3
    Last Post: 12-12-2015, 11:29 AM
  3. Replies: 7
    Last Post: 12-07-2012, 10:44 PM
  4. create connection to database in C
    By gmalachi in forum C Programming
    Replies: 2
    Last Post: 12-29-2010, 05:33 AM
  5. Replies: 3
    Last Post: 03-02-2008, 12:33 PM

Tags for this Thread